//
//  AirBSDSocketIO.h
//  AirCpp
//
//  Created by Penghao on 14-2-25.
//  Copyright (c) 2014年 PengHao. All rights reserved.
//

#ifndef __AirCpp__AirBSDSocketIO__
#define __AirCpp__AirBSDSocketIO__

#include <iostream>
#include "AirBSDSocket.h"
#include "../../AirString/AirString.h"
namespace AirCpp{
    template <class CallBack>
    class AirBSDSocketIO : public AirBSDSocket<CallBack>{
        
    public:
        int connect_to_host(AirString *const host, int port, CallBack *_target){
            if (AirBSDSocket<CallBack>::socketHandle<0) {
                DebugLog("socket isnot init,please init before! \n");
                return -1;
            }else{
                AirBSDSocket<CallBack>::callback_target = _target;
                
                AirBSDSocket<CallBack>::hostName = retain(host);
                
                AirBSDSocket<CallBack>::target_addr->sin_family = AF_INET;
                AirString *ip_addr = AirBSDSocket<CallBack>::get_ip(host);
                if (NULL == ip_addr) {
                    DebugLog("cannot find ip from host %s ,please check your url or network! \n", host->c_str);
                    return -1;
                }
                
                AirBSDSocket<CallBack>::target_addr->sin_addr.s_addr = inet_addr(ip_addr->c_str);
                AirBSDSocket<CallBack>::target_addr->sin_port = htons(port);
                bzero(&(AirBSDSocket<CallBack>::target_addr->sin_zero), 8);
                
                int conn = connect(AirBSDSocket<CallBack>::socketHandle, (struct sockaddr*)(AirBSDSocket<CallBack>::target_addr), sizeof(struct sockaddr));
                if (conn == -1) {
                    perror("connect failed!\n");
                    return -1;
                }else{
                    DebugLog("connect sucess!\n");
                }
                return 0;
            }
        }
        
        AirBSDSocketIO(CallBack *call_back):AirBSDSocket<CallBack>(call_back){
        }
        
        void link_to_handle(int socket_handle, CallBack *_target){
            AirBSDSocket<CallBack>::socketHandle = socket_handle;
            FD_SET(AirBSDSocket<CallBack>::socketHandle, &this->fdconn);
            AirBSDSocket<CallBack>::callback_target = _target;
        }
        
        AirSize_t write_data(AirBit8 *c_data, AirSize_t length){
            printf("send data:length = %d\n", length);
            AirSize_t dataSended = (AirSize_t)send(AirBSDSocket<CallBack>::socketHandle, c_data, length, 0);
            return dataSended;
        }
        
        AirSize_t read_data(AirBit8 *c_data, AirSize_t length){
            return (AirSize_t)read(this->socketHandle, c_data, length);
        }
        
        void reseive(){
            AirSize_t read_size = 0;
            FD_SET(this->socketHandle, &this->fdconn);
            do {
                this->status=select(this->socketHandle+1, &this->fdconn, 0, 0, this->tm);
                if(this->status > 0 && FD_ISSET(this->socketHandle, &this->fdconn)){
                    AirString *str = new AirString();
                    str->init(1024);
                    read_size = read_data(str->c_str, 1024);
                    str->length = read_size;
                    AirBSDSocket<CallBack>::callback(CALL_BACK_TYPE_SOCKET_RESEIVED, str);
                    release(str);
                }else if (this->status == -1){
                    AirBSDSocket<CallBack>::callback(CALL_BACK_TYPE_SOCKET_RESEIVED_TIMEOUT, NULL);
                    break;
                }else {
                    AirBSDSocket<CallBack>::callback(CALL_BACK_TYPE_SOCKET_RESEIVED_TIMEOUT, NULL);
                    break;
                }
            } while (read_size>0);
        };
    };
}

#endif /* defined(__AirCpp__AirBSDSocketIO__) */
